{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Copyright 2016-present, Facebook, Inc.\n",
    "# All rights reserved.\n",
    "\n",
    "# This source code is licensed under the license found in the\n",
    "# LICENSE-examples file in the root directory of this source tree."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Evaluate pysparnn on Enron data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import time\n",
    "import inspect\n",
    "\n",
    "from scipy.sparse import csr_matrix\n",
    "from sklearn.datasets import fetch_20newsgroups\n",
    "from sklearn.neighbors import LSHForest\n",
    "from sklearn.feature_extraction import DictVectorizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# make sure you run 'python setup.py install' first!\n",
    "import pysparnn.cluster_index as ci"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Get data"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "# fetch data\n",
    "\n",
    "\n",
    "!wget https://www.cs.cmu.edu/~./enron/enron_mail_20150507.tgz\n",
    "\n",
    "\n",
    "_ = !tar -xzvf enron_mail_20150507.tgz"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# load enron data \n",
    "import os\n",
    "import sys\n",
    "\n",
    "docs = []\n",
    "max_docs = 100000\n",
    "for folder, subs, files in os.walk('maildir'):\n",
    "    for filename in files:\n",
    "        with open(os.path.join(folder, filename), 'r') as src:\n",
    "            try:\n",
    "                txt = ' '.join(src.readlines())\n",
    "                if len(txt) > 0:\n",
    "                    docs.append(txt)\n",
    "            except:\n",
    "                pass\n",
    "        if len(docs) > max_docs:\n",
    "            break                \n",
    "    if len(docs) > max_docs:\n",
    "        break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Num docs: 100001\n",
      "Avg doc length: 413.757442426\n",
      "Num unique words: 942676\n"
     ]
    }
   ],
   "source": [
    "print('Num docs: {}'.format(len(docs)))\n",
    "print('Avg doc length: {}'.format(np.mean([len(x.split()) for x in docs])))\n",
    "words = set()\n",
    "for doc in docs:\n",
    "    words.update(doc.split())\n",
    "print('Num unique words: {}'.format(len(words)))\n",
    "del words"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Turn documents into vectors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from sklearn.neighbors import LSHForest, NearestNeighbors \n",
    "from sklearn.feature_extraction.text import TfidfVectorizer\n",
    "\n",
    "tv = TfidfVectorizer(decode_error='ignore')\n",
    "\n",
    "features = csr_matrix(tv.fit_transform(docs))\n",
    "\n",
    "doc_index = np.array(range(len(docs)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "test_features = features[:2000]\n",
    "train_features = features[2000:]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create an answer key"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "NearestNeighbors(algorithm='brute', leaf_size=30, metric='cosine',\n",
       "         metric_params=None, n_jobs=1, n_neighbors=5, p=2, radius=1.0)"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "knn = NearestNeighbors(algorithm='brute', metric='cosine')\n",
    "        \n",
    "knn.fit(train_features)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "67.97951602935791"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t0 = time.time()\n",
    "# get 1 NN for each document\n",
    "answers = knn.kneighbors(test_features, n_neighbors=1, return_distance=False)\n",
    "time.time() - t0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/spencebeecher/anaconda2/lib/python2.7/site-packages/sklearn/neighbors/base.py:211: UserWarning: cannot use tree with sparse input: using brute force\n",
      "  warnings.warn(\"cannot use tree with sparse input: \"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "52.95571780204773"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "bknn = NearestNeighbors(algorithm='ball_tree')\n",
    "        \n",
    "bknn.fit(train_features)\n",
    "\n",
    "t0 = time.time()\n",
    "# get 1 NN for each document\n",
    "_ = bknn.kneighbors(test_features, n_neighbors=1, return_distance=False)\n",
    "time.time() - t0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Build models to compare"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "114.92523193359375"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t0 = time.time()\n",
    "snn = ci.MultiClusterIndex(train_features, doc_index, num_indexes=2)\n",
    "time.time() - t0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "18.300570964813232"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t0 = time.time()\n",
    "lshf = LSHForest(n_neighbors=1)\n",
    "        \n",
    "lshf.fit(train_features)\n",
    "time.time() - t0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Compare results"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import pysparnn_utils\n",
    "import time "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Recall: 0.965\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "23.034273862838745"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t0 = time.time()\n",
    "\n",
    "results = snn.search(test_features, return_distance=False)\n",
    "\n",
    "print('Recall: {}'.format(pysparnn_utils.recall(answers, results).mean()))\n",
    "\n",
    "snn_time = time.time() - t0\n",
    "snn_time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Recall: 0.9245\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "11.743115901947021"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# only search one index instead of 2\n",
    "t0 = time.time()\n",
    "\n",
    "results = snn.search(test_features, return_distance=False, num_indexes=1)\n",
    "\n",
    "print('Recall: {}'.format(pysparnn_utils.recall(answers, results).mean()))\n",
    "\n",
    "time.time() - t0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Recall: 0.7185\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "77.58664608001709"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t0 = time.time()\n",
    "\n",
    "results = lshf.kneighbors(test_features, return_distance=False)\n",
    "\n",
    "print('Recall: {}'.format(pysparnn_utils.recall(answers, results).mean()))\n",
    "lsh_time = time.time() - t0\n",
    "lsh_time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.3683130860568533"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# LSH is x times slower than snn\n",
    "lsh_time / snn_time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Track Pysparnn vs Bruteforce as a function of index size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/spencebeecher/anaconda2/lib/python2.7/site-packages/pysparnn/matrix_distance.py:117: VisibleDeprecationWarning: boolean index did not match indexed array along dimension 0; dimension is 100001 but corresponding boolean dimension is 1000\n",
      "  records = self.records_data[index]\n"
     ]
    }
   ],
   "source": [
    "snn_results = []\n",
    "\n",
    "for n in np.linspace(1000, 80000, 5):\n",
    "    feats = train_features[:n]\n",
    "    \n",
    "    ########## brute force ############\n",
    "    bf = NearestNeighbors(algorithm='brute', metric='cosine')\n",
    "\n",
    "    bf.fit(feats)\n",
    "\n",
    "    # get 1 NN for each document\n",
    "    t0 = time.time()\n",
    "    \n",
    "    answers = bf.kneighbors(test_features, n_neighbors=1, return_distance=False)\n",
    "    \n",
    "    bf_time = time.time() - t0\n",
    "    \n",
    "    \n",
    "    ########## snn ############\n",
    "    snn = ci.MultiClusterIndex(feats, doc_index, num_indexes=2)\n",
    "    # only search one index instead of 2\n",
    "    t0 = time.time()\n",
    "\n",
    "    results = snn.search(test_features, return_distance=False, num_indexes=1)\n",
    "    \n",
    "    snn_time = time.time() - t0\n",
    "    snn_recall = pysparnn_utils.recall(answers, results).mean()\n",
    "    \n",
    "    # results\n",
    "    snn_results.append({\n",
    "            'n': n,\n",
    "            'snn_recall': snn_recall , \n",
    "            'snn_time': snn_time,\n",
    "            'bf_recall': 1.0,\n",
    "            'bf_time': bf_time\n",
    "        })"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x206f66050>"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x206f2f710>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "pd.DataFrame(snn_results)[['n', 'snn_recall', 'bf_recall']].plot(x='n', ylim=(0, 1), linewidth=4,\n",
    "                                                                 title='Recall is roughly flat')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.axes._subplots.AxesSubplot at 0x206f95e90>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX0AAAEoCAYAAAC0OiEVAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsnXmcTuX7x9/XDGMfy8gWhqRIRElKMkokhMraQrK1SNu3\nVPoaUepX+baSJVtRopBSUsxEKQlFVEqW7OuMnTH374/7DI/xnGee2Z5l5nq/XvOac859nXN/znad\n+7nOfa5bjDEoiqIo+YOIYAtQFEVRAoc6fUVRlHyEOn1FUZR8hDp9RVGUfIQ6fUVRlHyEOn1FUZR8\nRJ52+iLylIiMDbaOvIyIFBaRuSJyQESm58D2monIlpzQlg0NF4nIShFJEpEHg6hjtIg8E6z6g0H6\n8y8ia0TkuiBpSRWRC4JRd25SINgCsoOIHATSPjQoBhwHTjnL+hljRgRLWz7iduA8oLTJuY8+cvTj\nERFJBS40xmzwc5UngIXGmAY5qSOzGGPuC2b9QeT0+TfGXBoKOvISYd3SN8aUMMZEG2OigU1AG49l\nHwRbX1YQkcgg15/ZayIW+DMrDj8n9tVPvZnVFgv8lgU5QT9/GRHq+kIBj2MkQRWSWxhj8sQf8A9w\nfbplQ4D3nOlYIBXoCWwG9gL9gIbAL8A+4M106/cC1jq2XwBVXepO23YfYKvz95hHuQCDgL+A3cCH\nQKl06/bCPrgSXOr4D7AN+Be4x1nnAqdsEdDLw7YHsNhjvhbwlbMf64BOHmUTgVHA58BB4HFgByAe\nNrcCq7xoisf+ujoBJDu6BBgMbHS2MwmI9ndfgWbAFuAp51htALr70Hu9r/0HEp06DzkaOznL2wIr\ngf3AEuBSZ/k3QApw1LG/EIgGpgC7sNfZM+nqWgKMBPYAzznL+zjXTjKwBqjvLK8IzHS29TcwwMc1\nPdFje2nH5VFgJ/Ya6+lhWxh41Tnu+4FvgUJuxxxoDHzn2K4Emnlsq6eH9r+Avh5lMcBcZ729QKJH\nmeu+AVcCPwFJwHbgFZd9bgZs9nZfY+/n6cBkR9tq4PJM1P+9o3sr8CZQwKM8Fbgf+BP422PZBVgf\n4dc9EQ5/QReQYzvi7vSnONNpF/8oIApogb2xP3Eu5ErOzdTUsW/vXAAXYX8RPQ1851J32ranOjff\npc6Fl3axDnQuuIpAQWA0MC3dupOAIkAhL9u/yblRajs2U7FhLF9O/1tnuij2IXc31iFfhnWmtZzy\nic6N0NiZL4R1Uq08tvcJ8LDLvp8+xs58L+e4xTp1f+zlHPja12bASeBl51hdh3XYNX3odd1/Zz4V\nqO4x38A51w2dY3KXc/0UdDmeU4BZzv7EAn8A93jUdRLrMCIcPZ2wDvpyx+YCoIpT13LgGSASqIZ1\nqje6HNv0Tv+kc7wjgdbAYaCkU/42sBCo4NTT2Dl+5xxz7LW+J+0cAzc48zHOfGugmjPd1Kkn7aH1\nAvYeinB0NHGW+9w37PV/h8c12chlnzNy+keAVk59LwBL/az/cqCRY1cV+0vuoXTXyHygFM51ydkN\nK7/viVD/C7qAHNsR/5z+KaCCR/kezm71zky7EIB5ODe2Mx/hXPxVvNSddmPV9Fj2EjDOmV4LNPco\nq4htHUd46Ir1sW/vAi94zNfEf6ffGY/WmLPsHeBZZ3oiMCld+RPA+850GWe/y7toS+/0vwb6e8xf\nlMl9bebYF/ZYNh2nde2i1x+nf4HH/ChgaLpt/M6ZB/7p7Tm6jwMXe9j2xcb80+ramG5bX+KlBY91\nOultBwHvuhyL9E7/MBDhUb6TM47sCM6vFS/X5lnH3Dm/k71ovstFx6y0/QGGOvM1MrNv2F9cQ3Ae\nLBmcf19O/yuPstrAYWf6qkwe24HAx+mukWbpbDydvt/3RKj/hfWL3Cyyy2P6KPbG8Zwv7kzHAq+L\nyKvOvGBjw+djW3HpMdjQSxqbsC3+tG3Ncl4opm3rJFDew95z3fRUwrZiPLftb7wxFmgsIvs86o7E\ntl7TSL8/7wNrRaQI9qHxrTFmJ/5RydHnqbUA/u8rwH5jzLF026jkQ29miQXuFpEBzrxgW8WVvNiW\nxerfnE7P+T70VMGGF7zVe366cxGBDcX4w15jTKrH/BHs9VoW24L39aLa85jHAp1FpJ2HjgLYXwqI\nSGvgv5z5lVsE+NWxfRkb1vtKRAy2YfOSH/vWCxgG/C4iG7APs8/93G9PdnhMHwEKO+91qvqqX0Rq\nYkNwDZ39KQD8nG7bvq7L7NwTIUV+dPr+sgUYbvx/ISzYm/1PZ74qNgYP1mH0MsYsPWclkVhn0vjY\n9nZn22nEprM/jP3JnEYFj+kt2DhuKx/bP6tuY8w2EVkK3AbciW0Z+8s2R5+n1pPYh2vaPvjaV4DS\nIlLEGHPUma+Kjd961Yvv/ffGFuB541/vrj1Y/bHYXwM401t96NkC1HCpd4Mx5mI/6s0Me4BjTp2r\nXWw8NW7B/jrrl95IRKKwv3jvBOYYY1JFZBZOI8MYcwj73udxEbkEWCQiy8hg34wxfwPdnTpuA2aK\nSBmPc5xdMjq2o4EVQBdjzBERGYi9vs+S6bbxbN4TIUVY997JApl5G/8O8LRzYSMiJUXk9gzWeVZE\niohIHexLzQ+d5WOAF0SkqrOt80Tklkzo+gjoKSK1RaQothXmySrgVqfuC4F7Pco+Ay4SkTtFpICI\nFBSRhiKSkeN5D/uT9lJs/NJfPgAeEZFqIlIceB740KOF6s85EGCoo7Up0AZ7DNzwtf9gW4ee/a3H\nAf1FpBGAiBQTkZtFpFj6DTu6PwKeF5HizkP6EezxcWM81ile7my/hohUAZYBB0XkCef7hkgRqSMi\nDX1sK0OMjTlMBEaKSEURiRCRxiJS0DFJf8zfB9qJSEvHtrDTP74S9n1XFLDHcfitgZZpK4pIGxFJ\ne6AdxL70Ts1o30TkDhEp66yXhHWwnr9askravmV0bEsAyY7DrwVkpTtsVu+JkCIvOf2MWo/ebFzn\njTGzgReBD0XkAPbn7U0ZbD8R+/JoAfB/xphvnOWvA3OwP4mTsC+1Gvmr3RjzJfAa9uf3n9geJp78\nD9sa3YG9+d/3WPcQ9qbtim2Fb3P2q1AG+zIL26L9JF2oJSMmYG+Ob7EhjiPAQ56748c2tmNf1m5z\nttXPGLPex/qu++8QD0wRkX0icrsx5mds75q3nHDAn9jYvJvGh5z92ODs1/vGmIlu4o0xM7EPu2ki\nkow9lmWcB0hboD42Vr0L+wCKdttWBnjqfBzbyv8J26vmRc7c3+l/yf2L7ajwNPal/iZn/QjnenkI\nmOEcm67YazeNmsDXzjcy3wFvG2MS/di3m4DfnOPxP2yL+3gm99G13I/6HwfucOofw5kGma960i/L\n6j0RUojzYkLJBk7rbwO290dOtF78qTOzHxxlpY607noLc6sORQkn8sI9kZda+sEmT33I4cRdU8P5\n4laUnCSv3BP6IjfnCPRPplyrT0QWYbvD3ZlbdShKOJGX7gkN7yiKouQjNLyjKIqSjwh5px8qaW7D\nFRGpIiLJIpKn3jmEAyIyRER8de3M7vYXiUgvZ7q7iHzpUZYn0wIr2SfknT5n0tyWNMa8FWwx4YYx\nZouxWUcNnO0olICQpfipiPQQkcV+V2LMNGOMZ5dijdsGAedBPyVjy+ARDk4/ljya5tYb4aY53PSG\nEWlpP7Kzfr4ju9djvrieg538x9cfOZTmNt02hwAzsB9nJGNz2tR1yh4HZqazfwP4nzPdE/vBUbLz\nv1u6et8EDmATrF3vsY2euKeqbYb9hPwJ7EdJk8k4je5E4C3s17bJwFI8skim0x+L/fIxAhjuHM8j\nznpvuKxzNzZF725smuT0Sa9mYD+aOoDNqRKF/XhsKzZ/yf84k7EyAejoTDdxtLR25q8HVjrTNRzb\nA865/cBFWyGn7j3YD7h+BM5zyipiPyTai/3gqne68/6Rs24yNp12TWxSrp3YD5RaeNhHY7+s3eac\ni2Gc6fiwEWjgTN/h7FNtZ74X9uOdtDp9pQJ+0rke0tIvd3CW18Je8yexX73uczkWiziTGK4HZ6fT\n9kwWdi02Fch1Htv3mmrbSx09cbl2vdi6nkPgRqeu/dj7JMFD+xCcFOjpr9ms3D/O8vSps+v60O0t\nrfI12K98066xqz3svV5n2Oyfx52/gzjXdqj9BV1AhgKzmebWy/aGOCelIzbx2GPYD6sisTlbDnIm\n/3sk1iHUd+pLwn4QBTaBWO109T7krNPZufDTcub7SlXbzFn3BWzSr0JknEZ3ItYhX+Hs5/s4qZq9\n7G8sNstihLfj6cX+EucYXI3t0vuyc7yuT3f82jnzhYHnsF8Zxzh/3+FkscRmZXzdmX4KWA+M8ChL\ne6BOA55ypqOAa1z09XVuuELY1mwDoLhT9i3WoRTEppDeBcR56D6CTakdgXXEGxxNkUBvbO6WtHpm\nYfOrFMYmNPsB6OOUTQYecabHOPvUz6NsYLo6z0kF7JTfhpOpEZuO+ZDHfA88MoVmdG+kt+dMLvib\nsA+0K5zl3lJt78JJte2lDtdr14ut13PoXBPJnLnnHsZmUvV0+p6ZWtNfs5m9f3ymzvaiOy2tckln\n/dLY8TW6O9dKV2e+tJ/X2RRv9YTKX9AFZCgwm2luvWxvCPC9x7xgW3NpecE/B+51ptsCazxuln3O\nhVs43TZ7AP+mW/YjTv5wLxo8U9U2wybLKuhR3gyXNLrO9ERgrEdZa2CtS12ZdfrPAlM95otwrtNP\nSLfOX5yda7wljgPFtuZXOdNfYFvC3zvzCZxp3U7G5js6P4Pzdw9eWm5AZezNX9Rj2QvABA/d8z3K\n2mIdUVrrvbhznKKxD/RjeDQasDd+2nXWC5jtTK915tPGR9jIGYc0BJdUwC77tpIzD9OccPqDsM6u\ntsdyn6m2/bgfT1+7Xsq8nkOs0/0+3bIt+On0s3D/+Eyd7WV7Z6VVxvbF/yGdzffYB6U/11lIO/1w\niOl7kpU0t944bWPsmfqXM2l1p3DmA4w7cBJrGWOOAF2wiZq2ix0M3DNpmWfWxTRdlcCmqhWRpSKy\nV0T2Y510WQ/b3caYk+nWd0ujm0b6FLOeZdmhEmcfn6PYn7GepD/GlTj3nKQdz6XYhG/lsK2iKUAV\nEYnB5h9KS737H+xDfZmIrBaRe1z0TcG2yj4UkX9F5EUnDlsJGwY5kk6H57WRPo32Huf8p80L9jhW\nxbbitjv5evZjnVnaOUsEmopIBUfzR8C1TjqOaGPMKo963FIBIyJ3Oz3T9jt11OHs6yK7DAQ+Msas\n81gWi5Nq22PfuuOSmdSPa9cTt3N41jXl4Hd67CzcP7HAY+n2sTLeU2en4ZlWOX16cDhzLflznYU0\n4eb0PdPcphGL7zS33jidptjpyliZM2mQZwP1xGbKbIsdpcpu2JgFxpiW2BvkD2CsxzbTn/SqwDY5\nk6r2/7Cx59LYFq/nizZ/NOcUGdW1HXs8ABCbPzwmg21s5dxzsg1OPzR+xjqgNcaYFOyD4FHgL2PM\nPsdulzGmrzHmfKA/MMpbl0NjzCljzDBjTB1s3LUdtgW2DSiTLlNmVc59GPvDFmzrMcYYU8YYU9oY\nU8oYU8/R8Df2ITEA27o+hHXufbG/QjJEbMbVscD9zvZLYzsspF0X2b0mDDZk1FFEPBPepaXaLuOx\nb9HGmAe8aPTn2j1Tofs53I49F554pgpPnxq7YiY1pD9WaamzPfexuDFmujfdXraxDTvylidp11JG\n11kg7+UsEVZO32Qtza03rhCRDk4L8RHsDf6DU8dx7BB/04Afjc1IiIiUE5FbxKY2PomNv3q2xMuJ\nyACx6Ys7YV+WfU4GqWoDhOcNspOz0wynZyY27W5aat54P7b/ITBYRMo66XOf5exz8i3wILaFDDas\n4zmPiNwuImkPzgPYY3tO8joRiRORS53W8iHsuTjlnKfvgREiUkhE6mFTLGe6n7wxZgf2Ref/RKSE\nWC4Qkes8zBIz2icX0s5FMWf/9ohNb3wPZwbdAXueKsuZ9MiZJS1seQPwkIj0d5a7pdqu5WUbmbp2\nfZzDz4FL0u45sbnsPQfVWQVc53xTUhIblsqSBge/U2e7MA+oKSJdHb1dsKG5uX5cZzuBaqH8XUw4\nOP30T85Mpbl1YQ42VLMfG8LpaIw55VE+GajL2aNLRWBbp1uxvziu4+yc3D9ie4Pswfb0uM0Yc8Bk\nnKrWX7LTgvBc93Wgk/NT+bVzDI1Zi23BTsc6jWTsiypfaXCHY3tB/YrtFbMcm1o4jURs2OTbdPOe\nDvJK4EexqW9nY4et3OilrgrYB1MStmW8iDOplLsB1R3dH2Pj1It86E6P53G6G+ts1mLf5czg7BCI\n2z5lNAqWAXBCLq9iGxs7sKEdz18JC7H7t0NEdqXfiBe9bvVswb68flJEehn3VNtR52wg89eu13No\njNmL/dXxEvb+qIF92Z9Wz9fY6+1XbGroudnQgMk4dfY5q6Rbfx/2V/7jjt7HgTbGmP2Oia/rbAb2\ngbtXRDxHuwsZ/M6947SslmNfWN4iIqWxJyoW+/KqszEmKbeE5hQiMgQ7vufdPmyqYLuXVXAuuoy2\n2QP78ve6jGzDDad1dADbayl9nFNRsoTYBGbvGWMmBFtLfiMzLf2B2FZPGoOAr40dnmwhtutb2OM8\n3B7DjvaUocPPi4hIW7GjUBXDtkZ/VYevKHkDv5y+iFQGbsZ+rJJGe2wYBOd/h5yVFniceH0Stpvh\nkCDLCSbtsT9d/8X+FO8aXDlKHiTkX3jmVfwK74jIDGyMtiTwmBPe2e+8SU+z2WeMKZN7UhVFUZTs\nkmFLX0TaADudvse+3kjrk1tRFCXE8WfkrCbALSJyM/brzBJi08XuEJHyxpidzkcqXnsYiIg+DBRF\nUbKAMSbHu35m2NI3xjxtjKlqjLmAM5+i34XtVtXTMeuBj25Uwfrc2NffkCFDgq4hL+kMJ63hojOc\ntKrOzP2lpqbyweoPiHkpxn4J4+0vl8jOGLkvAh+Jzc2+CZvTQ1EURfHBrsO7uP/z+/l43ceuNuWK\nlWOX9+BJtsnUx1nGmERjzC3O9D5jTAtjzMXGmJbGmAO5olBRFCWPMOO3GdQZVcenw+9Spwu/3Z+l\nIUT8Ijst/bAmLi4u2BL8Ilx0QvhoDRedED5aVadvdh/ezQPzHmDG2hmuNmWLlmV0m9HcfsntuarF\n7y9ys1yBiMntOhRFUUKVT9Z9Qv/P+rP7yG5Xm9svuZ23b36bcsXKnV4mIphceJEbtJZ+tWrV2LRJ\nP/IMNrGxsWzcuDHYMhQlz7H3yF4GfDGAD9Z84GoTUySGUW1G0blO4F6JBq2l7zzFcrVuJWP0PChK\nzjPn9zn0+6wfOw/vdLXpWKsjo9uMpnzx8l7L81xLX1EUJa+x7+g+HvriIaaunupqU7pwad66+S26\nXdqNYGRgVqevKIqSA8z9Yy59P+vLjkM7XG1uufgW3mnzDhVLVHS1yW3U6SuKomSD/Uf38/D8h5ny\nyxRXm1KFS/Fm6ze5o+4dQWnde6JOX1EUJYvMWz+PPnP7sO3gNlebNjXbMLbdWCqV8DVEb+AIh5Gz\n8h0jRoygb9++wZahKIoLSceS6DWnF22mtXF1+CULlWRi+4nM7TY3ZBw+aO+doJOYmMidd97Jli1b\nglK/ngdFyRzz/5pP77m9+Tf5X1ebmy68iXHtxlE5unKW68k3vXdyK9wVqn7NGBP0GJ+iKBmTfDyZ\nx+Y/xviV411togtF879W/+Oe+veE7H2t4R0XXnrpJSpXrkx0dDS1a9dm0aJFDB06lC5dutCjRw+i\no6OpW7cuK1asOL1O9erVefXVV7nssssoXbo03bp148SJE651HDlyhJtvvplt27ZRokQJoqOj2bFj\nB0OHDuWuu+4CYNOmTURERDBp0iSqVq1KTEwMY8aMYfny5Vx22WWUKVOGAQMGnLXdCRMmcMkllxAT\nE0Pr1q3ZvHlz7hwkRcknLPh7AZeOutSnw29ZoyVr7ltDrwa9Qtbhgzp9r/z555+8/fbb/PzzzyQn\nJzN//nyqVasGwNy5c+nevTtJSUm0a9eOBx544Kx1Z8yYwVdffcU///zDL7/8wqRJk1zrKVq0KF98\n8QWVKlXi4MGDJCcnU6FCBYBzLpply5bx119/MX36dB5++GFeeOEFFi5cyJo1a/joo49YvHgxAHPm\nzOHFF19k9uzZ7N69m6ZNm9KtW7ecOziKko84ePwg/T/rT8v3W7Il2XsItnhUcca2HcuXd3xJlZJV\nAqww86jT90JkZCQnTpxgzZo1pKSkULVqVapXrw7AtddeS6tWrRAR7rrrLn799dez1h04cCDly5en\nVKlStGvXjlWrVmVbj4jw3//+l6ioKFq0aEGxYsXo1q0bMTExVKpUiaZNm7Jy5UoAxowZw1NPPcVF\nF11EREQEgwYNYtWqVUF7Z6Ao4crCfxZSd3Rdxvw8xtXmhuo3sOa+NfS5ok9It+49UafvhRo1avDa\na68RHx9PuXLl6N69O9u3bwc43RIH21I/duwYqampp5eVL1/+rPJDhw7liKZy5c4kYipSpMhZ9RQp\nUuR0PZs2bWLgwIGUKVOGMmXKEBMTg4iwdevWHNGhKHmdQycO8cDnD3DDlBvYlOQ9P1ixgsUY3WY0\nC+5aQGyp2AArzB4h5/SNyZ2/zNK1a1cWL158Oh7+5JNP5vCeWnK6dVClShXGjBnDvn372LdvH/v3\n7+fQoUM0btw4R+tRlLxI4sZE6o2ux6jlo1xtmldrzur7VtO/Yf+wad17EnJOPxT4888/WbRoESdO\nnCAqKooiRYoQGRnp1Ta73R3Lly/P3r17SU5OdrXJTB39+/fnhRdeYO3atQAkJSUxc+bMbGlUlLzO\n4ROHeeiLh4ibHMc/B/7xalO0YFHeav0WX9/9NdVLVw+wwpxDnb4Xjh8/zqBBgzjvvPOoVKkSu3fv\nZsSIEV5tPZ/0WXnqX3zxxXTr1o0LLriAMmXKsGPHuXk70m/X13yHDh0YNGgQXbt2pVSpUtSrV48v\nv/wy07oUJb+weNNiLnvnMt5c9qarzXWx1/Fr/195oNEDREh4u039OCufo+dBya8cOXmEZ755htd/\nfB2D93ugSIEivNjiRR5s9GDAnX3QPs4SkULAt0CUYz/TGDNURIYAfeD06L1PG2O0SakoSsjz3ebv\nuGfOPazft97VpkmVJkxsP5GaMTUDqCz3yfDRZYw5DjQ3xjQA6gOtRaSRUzzSGHO586cO34URI0ac\n/vjK869NmzbBlqYo+YqjJ4/y+FeP03RiU1eHX7hAYUa2HEliz8Q85/Ahk+EdESmKbfXfB9wMHDLG\nvJrBOhreCWH0PCj5hR/+/YGes3vyx94/XG2urnw1E9tP5OKyFwdQmXdyK7zjV5BKRCJEZCWwA1hg\njPnJKXpQRFaJyHgRKZnT4hRFUbLLsZRjPLngSZpMaOLq8AtFFuLlG19m8T2LQ8Lh5yaZbelHA7OA\nAcBuYI8xxojIcKCiMeZeL+toSz+E0fOg5GWWbV1Gz9k9WbdnnatNo/MbMan9JGqfVzuAyjImJLJs\nGmOSRSQBuMkYM9KjaBww1229+Pj409NxcXHExcVlSqSiKEpmOJ5ynKGJQ3npu5dINalebaIio3gu\n7jkeu+YxCkQEP+FwQkICCQkJuV5Phi19ESkLnDTGJIlIEWA+8CKwwhizw7F5BLjSGNPdy/ra0g9h\n9DwoeY3l25bTc3ZPftv9m6tNw0oNmdR+EnXK1QmgsswRzJZ+RWCyiERg3wFMN8bME5EpIlIfSAU2\nAv1yWpyiKIq/nDh1gmGJwxixZASnzCmvNgUjChIfF88TTZ4IidZ9MPCny+Zqp0tmfWNMPWPM887y\nu535+saYDsaYnbkvNzBUr16dhQsXei0bPXo0FSpUIDo6mv379/u9zSVLllC7dmjFDBUlr7Bi+woa\njm3I8MXDXR3+5RUv5+e+P/N006fzrcMHTcOQKVJSUnjsscf4+uuvSU5OpnTp0q62ERERbNiw4fT8\ntddey7p17i+TFEXJPCdOnWDIoiFcNf4qVu9a7dWmYERBhjUfxg/3/kDd8nUDrDD0CLnHnQzNnax1\nZkj249Y7duzg+PHjfrXYwzH7nqKEE7/s+IUes3vwy85fXG3qV6jPpPaTuKzCZQFUFtpoS9+FZcuW\nUadOHWJiYrj33ntZvXo1tWrVAqB06dK0aNHCdd1mzZphjKFevXpER0czY8YMEhMTqVLlzKg61atX\n55VXXuGyyy6jRIkS9OnTh127dnHzzTcTHR1Ny5YtSUpKOm3/ww8/0KRJE0qXLk2DBg1ITEzMvZ1X\nlBDm5KmTDEscRsNxDV0dfoGIAgxpNoQfe/+oDj8dIdfSDxWmTZvGggULKFq0KG3btmXGjBmsXbuW\n6tWrk5SU5LMln5iYSEREBKtXrz494lZiYuI563zyySd88803nDx5kvr167Ny5UomTJhArVq1aN26\nNW+88QbPPvssW7dupW3btkydOpVWrVrxzTffcNttt/HHH38QExOTq8dBUUKJ1TtX03NOT1ZsX+Fq\nU7dcXSZ3mEyDig0CqCx80Ja+CwMGDKBSpUqUKlWKZ555hg8++OB010Z/uzhmZDdgwADKli1LxYoV\nadq0KVdddRX16tUjKiqKjh07nh4CcerUqbRp04ZWrVoBcMMNN9CwYUPmzZuXjT1UlPAhJTWF5799\nnivGXuHq8CMlkmeve5blfZerw/eBtvRdqFy58unp2NhYtm3bBmR/0BRP0g956GsIxI8++oi5c+ee\n1pCSksL111+fY1oUJVT5bddv9JzTk+Xblrva1DmvDpM7TOaKSlcEUFl4EnJOPydeuOYEngOJb9q0\niUqVKgHBeUFbpUoV7r77bsaMcR+gWVHyGimpKbzy/SsMSRjCiVMnvNpESARPNnmSIc2GUKhAoQAr\nDE80vOPC22+/zdatW9m3bx8vvPACXbt2Bfxv6VeoUOGsLpvZ4c4772Tu3Ll89dVXpKamcuzYMRIT\nE0//+lCUvMa63etoMqEJT33zlKvDr122NkvvXcoLN7ygDj8TqNP3gojQvXt3WrZsyYUXXkjNmjV5\n5plnTpcnv1OuAAAgAElEQVT5Q3x8PHfffTdlypTxOkZtRkMgelK5cmXmzJnDCy+8wHnnnUdsbCyv\nvPIKqanec4ooSrhyKvUUL3/3Mg3GNGDZ1mVebdJa9yv6raDR+Y282iju6HCJ+Rw9D0qo8MeeP7hn\nzj0s/Xepq83FMRczqcMkGlduHEBlwSEksmwqiqLkNKdST/H6j6/zzMJnOJZyzKuNIDx29WM81/w5\nihQsEmCFeQt1+llkyZIltG7d+qywjDEGESE5OTmIyhQlfFi/dz33zLmH77Z852pTs0xNJrafSJOq\nTQKoLO+i4Z18jp4HJRikmlTe/PFNnvrmKY6mHPVqIwgPN36Y4dcPp2jBogFWGHw0vKMoSp7gr31/\n0WtOLxZvXuxqU6N0DSa2n0jT2KYBVJY/UKevKEpASDWpjPppFE9+/SRHTh5xtXuo0UO8cMMLFIsq\nFkB1+YegOf3Y2FjNRBkCxMbGBluCkg/4Z/8/9Pq0FwkbE1xtqpeqzsT2E2lWrVnghOVDghbTVxQl\n75NqUhmzfAz/WfAfDp887Gr3wJUP8GKLFykeVTyA6kIbjekrihJWbDywkXs/vZeF/3gfhQ4gtmQs\nE9pP4PrqmkcqUKjTVxQlRzHGMPbnsTy+4HEOnTjkatf/iv78343/R4lCJQKoTsnQ6YtIIeBbIMqx\nn2mMGSoipYHpQCx2YPTOxpgk1w0pipLn2Zy0md6f9mbBhgWuNlVLVuXdW96lxQXuAxEpuYdfMX0R\nKWqMOSIikcB3wEPAbcBeY8z/iciTQGljzCAv62pMX1HyOMYYJqycwCPzH+HgiYOudn0u78MrLV8h\nulB0ANWFJ0GN6Rtj0vpXFXLWMUB7IO01+2QgATjH6SuKkrf5N/lf+sztw5d/felqUzm6MuPbjafV\nha0CqEzxhl9OX0QigJ+BGsDbxpifRKS8MWYngDFmh4iUy0WdiqKEIAkbE+g0oxN7juxxtelVvxcj\nW42kZOGSAVSmuOFvSz8VaCAi0cAsEamDbe2fZea2fnx8/OnpuLg44uLiMi1UUZTQwRjD2z+9zcNf\nPswpc8qrTaUSlRjXbhw317w5wOrCk4SEBBISEnK9nkz30xeRZ4EjQG8gzhizU0QqAIuMMbW92GtM\nX1HyEMdTjnP/5/czYdUEV5sel/Xgf63+R+kipQOoLG+RWzH9DAdREZGyIlLSmS4C3AisAz4Fejpm\nPYA5OS1OUZTQYtvBbTSb1MzV4VcoXoFPu37KpA6T1OGHKBm29EWkLvZFbYTzN90Y87yIlAE+AqoA\nm7BdNg94WV9b+oqSB/jh3x+4dfqtbD+03Wv5tVWvZWanmZQvXj7AyvImudXS1zQMiqJkyLsr3uX+\nefe7jld7X8P7eO2m14iKjAqwsryLpmFQFCXgnDx1kkfmP8LbP73ttbxgREHevvlt+lzRJ8DKlKyi\nTl9RFK/sOryLTjM68e2mb72Wly9Wno87f6wjWoUZ6vQVRTmHFdtX0OHDDmxJ3uK1/MpKVzKryyzO\njz4/wMqU7JJh7x1FUfIX01ZPo8mEJq4Ov8dlPfj2nm/V4Ycp2tJXFAWAU6mnGPT1IF5Z+orX8kiJ\nZGSrkQxoNEAHQApj1OkrisK+o/vo9nE3vvr7K6/lMUVimNFpBs2rNw+wMiWnUaevKPmcNbvW0OHD\nDvy9/2+v5ZeVv4zZXWdTrVS1wApTcgWN6StKPmbWulk0Ht/Y1eF3qdOF73p9pw4/D6FOX1HyIakm\nlSGLhnDrR7d6HbtWEF684UU+uO0DikUVC4JCJbfQ8I6i5DOSjydz5yd3MvfPuV7LSxYqyQe3fUDr\nmq0DrEwJBOr0FSUf8efeP2n/YXt+3/O71/LaZWszp+scasbUDLAyJVCo01eUfMK89fPo/nF3ko57\nH8r6lotv4b2O7+lQhnkcjekrSh7HGMOLS16k7bS2rg5/SLMhzOoySx1+PkBb+oqShzl84jC9Pu3F\nR7995LW8eFRxpnSYQsfaHQOsTAkW6vQVJY+y8cBGOnzYgV92/uK1vEbpGszpOoc65eoEWJkSTNTp\nK0oeZOE/C+k8ozN7j+71Wt6yRks+vO1DHd0qH6IxfUXJQxhjeP2H12n5XktXh/+fa/7DvO7z1OHn\nU7Slryh5hGMpx+j/WX8m/zLZa3nhAoV595Z36V63e4CVKaGEOn1FyQP8m/wvt06/lZ+2/eS1vGrJ\nqszqMovLK14eYGVKqJFheEdEKovIQhH5TURWi8gAZ/kQEflXRFY4fzflvlxFUdLz3ebvaDi2oavD\nbxbbjOV9lqvDVwA/BkYXkQpABWPMKhEpDvwMtAe6AAeNMSMzWF8HRleUXGLsz2N5cN6DnEw96bX8\nwSsfZGSrkRSMLBhgZUp2CdrA6MaYHcAOZ/qQiKwD0obM0ZEUFCUInDh1goFfDOSdn9/xWh4VGcXo\nNqPp1aBXgJUpoU6GLf2zjEWqAQnApcBjQE8gCVgOPGaMOedzP23pK0rOsvPQTm6fcTtLNi/xWl6x\neEU+6fIJjSs3DrAyJScJWkvfQ0BxYCYw0GnxjwKeM8YYERkOjATu9bZufHz86em4uDji4uKyo1lR\n8i3Lty2n4/SO/Jv8r9fyxpUb83Hnj6lUolKAlSnZJSEhgYSEhFyvx6+WvogUAD4DvjDGvO6lPBaY\na4yp56VMW/qKkgO898t79Jnbh+Onjnst71W/F6PajKJQgUIBVqbkBrnV0vf346wJwFpPh++84E3j\nVmBNTgpTFMWSkprCo/Mf5e7Zd3t1+AUiCvBW67cYf8t4dfhKhvjTe6cJ8C2wGjDO39NAd6A+kAps\nBPoZY3Z6WV9b+oqSRfYe2UuXmV345p9vvJaXLVqWmZ1m0qxaswArU3Kb3GrpZ+pFbpYqUKevKFni\n152/0uHDDvxz4B+v5Q0qNGB219lULVk1wMqUQBDs8I6iKAFk5tqZXP3u1a4Ov9ul3VjSa4k6fCXT\nqNNXlBAi1aTyzDfP0GlGJ46cPHJOeYRE8PKNLzP11qkULVg0CAqVcEdz7yhKiJB0LIk7PrmDz9d/\n7rW8VOFSfHjbh7S6sFWAlSl5CXX6ihIC/L7nd9p/2J4/9/7ptbzOeXWY3XU2F5a5MMDKlLyGOn1F\nCTKf/fkZd3xyB8nHk72Wd6zVkckdJlOiUIkAK1PyIhrTV5QgYYxh+LfDueWDW1wd/nNxzzGz80x1\n+EqOoS19RQkCh04coufsnny87mOv5SWiSvD+re9zy8W3BFiZktdRp68oAWbD/g10+LADq3et9lpe\ns0xN5nSdQ+3zagdYmZIfUKevKAHk6w1f03lGZ/Yf2++1vPWFrZl22zRKFS4VYGVKfkFj+ooSAIwx\njFw6klbvt3J1+IOaDGJut7nq8JVcRVv6ipLLHD15lL6f9eX9X9/3Wl60YFEmtp9I5zqdA6xMyY+o\n01eUXGRz0mY6Tu/Iiu0rvJbHloxlTtc5XFbhsgArU/Ir6vQVJZdYvGkxt310G7uP7PZa3rxacz7q\n9BFli5YNsDIlP6MxfUXJYYwxjP5pNNdPud7V4Q+8aiDz75yvDl8JONrSV5Qc5HjKcQZ8MYBxK8Z5\nLS8UWYgxbcfQo36PACtTFIs6fUXJIbYf3M7tM27n+y3fey0/v8T5fNLlExqd3yjAyhTlDOr0FSUH\nWLZ1GR2nd2TbwW1ey6+pcg0fd/6YCsUreC1XlEChMX1FySaTVk3iuonXuTr8Ppf3YeHdC9XhKyGB\ntvQVJYucPHWSx796nDeWveG1vEBEAd5s/Sb9G/YPsDJFcSdDpy8ilYEpQHnsIOjjjDFviEhpYDoQ\nix0YvbMxJikXtSpKyLDnyB46z+jMoo2LvJaXK1aOmZ1m0jS2aYCVKYpvMhwYXUQqABWMMatEpDjw\nM9AeuAfYa4z5PxF5EihtjBnkZX0dGF3JU6zasYoOH3ZgU9Imr+VXVLyCWV1mUaVklQArU/ISQRsY\n3Rizwxizypk+BKwDKmMd/2THbDLQIafFKUqoMX3NdK559xpXh39nvTtZfM9idfhKyJKpF7kiUg2o\nD/wAlDfG7AT7YADK5bQ4RQkVTqWeYtDXg+j6cVeOphw9pzxCIhjZciRTOkyhSMEiQVCoKP7h94tc\nJ7QzExhojDkkIuljNq4xnPj4+NPTcXFxxMXFZU6logSRA8cO0P3j7nzx1xdey8sUKcP026fT4oIW\nAVam5CUSEhJISEjI9XoyjOkDiEgB4DPgC2PM686ydUCcMWanE/dfZIw5Z9QHjekr4cza3Wvp8GEH\n1u9b77W8brm6zO46mwtKXxBgZUpeJ2gxfYcJwNo0h+/wKdDTme4BzMlBXYoSdOb8Poerxl/l6vBv\nv+R2vr/3e3X4SljhT++dJsC3wGpsCMcATwPLgI+AKsAmbJfNA17W15a+ElakmlSGJQ4jPjHea7kg\nDGs+jKebPo1IjjfEFAXIvZa+X+GdbFWgTl8JIw4eP8jds+9m9u+zvZZHF4pm6q1TaXtR2wArU/Ib\nueX09YtcRXH4a99ftP+wPWt3r/VafnHMxczuOptaZWsFWJmi5Bzq9BUFmP/XfLp+3JUDx86JUALQ\npmYbpt46lZKFSwZYmaLkLJpwTcnXGGN4+buXuXnaza4O/5mmz/Bpt0/V4St5Am3pK/mWIyeP0PvT\n3nyw5gOv5cUKFmNSh0ncfsntAVamKLmHOn0lX7LpwCY6Tu/Iyh0rvZZXL1WdOV3nULd83QArU5Tc\nRcM7Sr7iVOoppvwyhYbjGro6/Buq38BPfX5Sh6/kSbSlr+QLUk0qH6/9mP8m/Jff9/zuavdo40d5\n6caXKBCht4aSN9ErW8nTGGOYt34egxcNZtWOVa52hSILMa7dOO667K4AqlOUwKNOX8mzLPxnIYMX\nDmbpv0t92lWOrsysLrNoWKlhgJQpSvBQp6/kOZZuWcozC59xHdXKk7YXtWV8u/GUL14+AMoUJfio\n01fyDCu3r2TwosHMWz8vQ9tmsc0Yfv1wrq16bQCUKUrooE5fCXvW7l7LkIQhzFw7M0PbRuc34vnr\nn+eG6jdosjQlX6JOXwlb/t73N/GJ8Uz9dSrGfQwfAOqVr8ew5sNod1E7dfZKvkadvhJ2bEnawvBv\nhzNh1QRSUlN82l4cczFD44bSqU4nIkQ/S1EUdfpK2LDz0E5GLBnBO8vf4fip4z5tq5WqxpBmQ7iz\n3p3a515RPNC7QQl59h3dx8vfvcwby97gyMkjPm0rlajE4KaDuffye4mKjAqQQkUJH9TpKyFL8vFk\nXvvhNV5d+irJx5N92pYtWpanrn2K+xreR5GCRQKkUFHCD3X6Sshx5OQR3l72Ni999xJ7j+71aVuy\nUEn+c81/eOiqhyhRqESAFCpK+KJOXwkZjqccZ9yKcTy/+Hl2HNrh07ZYwWI83PhhHrv6MUoXKR0g\nhYoS/mTo9EXkXaAtsNMYU89ZNgToA+xyzJ42xnyZayqVPE1KagpTfpnC0MShbE7a7NO2UGQhHrjy\nAZ689knKFSsXIIWKknfIcGB0EbkWOARMSef0DxpjRmZYgQ6MrriQalKZvmY6QxKGsH7fep+2BSIK\n0LtBbwZfN5jzo88PkEJFCR5BGxjdGLNERGK9acppMUr+wBjDnD/m8OyiZ1mza41P2wiJ4K56dzGk\n2RCql64eIIWKknfJTkz/QRG5C1gOPGaMScohTUoexRjDV39/xeBFg1m+bXmG9p3rdCa+WTy1z6sd\nAHWKkj/IqtMfBTxnjDEiMhwYCdzrZhwfH396Oi4ujri4uCxWq4Qr3276lsELB7N48+IMbdtd1I7n\nmj9H/Qr1A6BMUUKDhIQEEhIScr2eDGP6AE54Z25aTN/fMqdcY/r5mJ+2/sTgRYP56u+vMrRtcUEL\nhjUfRuPKjQOgTFFCm6DF9NPqxyOGLyIVjDFpfepuBXwHZpV8x+qdq3l20bPM+WNOhrbXVLmG569/\nnrhqcbkvTFHyOf502ZwGxAExIrIZGAI0F5H6QCqwEeiXixqVMOLPvX8yJGEI09dMzzDz5eUVL2d4\n8+HcdOFNmvlSUQKEX+GdbFWg4Z18wcYDG3ku8Tkm/zKZVJPq0/aS8y5hWPNhdKzVUZ29orgQ7PCO\nonhl28FtPP/t84xbMY6TqSd92tYoXYP4uHi6XdqNyIjIAClUFMUTdfpKlthzZA8vLXmJt356i2Mp\nx3zaVo6uzH+v+y896/ekYGTBAClUFMUb6vSVTHHg2AFGLh3J/374H4dOHPJpW75YeZ5u+jR9r+hL\n4QKFA6RQURRfqNNX/OLwicO88eMbvPz9y+w/tt+nbenCpXmyyZM82OhBikUVC5BCRVH8QZ2+4pNj\nKcd4Z/k7jFgygl2Hd/m0LRFVgkevfpRHGj9CycIlA6RQUZTMoE5f8crJUyeZsHICw74dxtaDW33a\nFilQhAGNBvBEkyeIKRoTIIWKomQFdfrKWZxKPcXU1VMZmjiUDfs3+LSNioyi3xX9eOrap6hYomKA\nFCpK3iU1FZYsgUmTcq8OdfoKYNMcf7LuE/676L+s27POp22kRNKzfk+eve5ZYkt5S8CqKEpm2LgR\npkyByZNhg++2VrZRp5/PMcYwb/08Bi8azKodq3zaCkK3ut2IbxZPzZiaAVKoKHmTw4fh449tq37R\nosDVq04/H7Pwn4UMXjiYpf8uzdC2Y62OPNf8OS4td2kAlClK3sSYM+Gbjz6CQ757PecK6vTzIUu3\nLGXwosEs/GdhhrY3XXgTw5oPo2GlhgFQpih5k82bbehm8mT4++/galGnn49YuX0lgxcNZt76eRna\nXhd7HcObD6dpbNMAKFOUvMeRI/DJJ7ZVv3ChbeX7gwjceCN8lXE28iyhTj8fsHb3WoYkDGHm2pkZ\n2jY6vxHDmw+nxQUtNBmaomQSY+C7786Ebw4e9H/diy6Cnj3hrrugcmXr/HMDdfp5mL/3/c3QxKFM\nXT01w8yX9crXY1jzYbS7qJ06e0XJJJs3w3vvWWf/11/+rxcdDV27WmffuHHuOXpP1OnnQbYkbWH4\nt8OZsGoCKakpPm0virmI5+Keo1OdTkRIRIAUKkr4c+QIzJplHf0332QufNOihXX0HTpA0aK5qfJc\n1OnnIXYe2smIJSN4Z/k7HD913KdttVLVGNJsCHfWu5MCEXoZKIo/GANLl1pHP306JCf7v+6FF1pH\nf/fdUKVKbinMGL3b8wD7ju7j5e9e5o1lb3Dk5BGfthWLV2TwdYPpfXlvoiKjAqRQUcKbLVvOhG/W\nr/d/vRIloEsX6+yvuSYw4ZuMUKcfxiQfT+b1H17nlaWvkHzcd5OjbNGyDGoyiPuvvJ8iBYsESKGi\nhC9Hj8Ls2TBxInz9debCN9dfD/fcAx07Bj58kxHq9MOQIyePMOqnUby45EX2Ht3r07ZkoZI8fs3j\nDLxqICUKlQiQQkUJT4yBH36wLfoPP8xc+KZGjTO9b2JDODuJPwOjvwu0BXYaY+o5y0oD04FY7MDo\nnY0xSbmoUwGOpxxn/IrxPL/4ebYf2u7TtljBYgy8aiCPX/M4pYuUDpBCRQlPtm61uW8mTYI///R/\nveLFoXNn6+yvvTY0wjcZkeHA6CJyLXAImOLh9F8C9hpj/k9EngRKG2MGuayvA6Nnk1STynu/vMeQ\nhCFsStrk07ZQZCHuv/J+Bl07iHLFygVIoaKEH0ePwpw51tEvWGAzXPrL9ddbR3/rrVAsl8YJyq2B\n0TN0+k7lscBcD6f/O9DMGLNTRCoACcaYWi7rqtPPBuv3rqfvZ31J2Jjg065ARAF6N+jNM9c9Q+Xo\nyoERpyhhhjGwbJl19B98AEmZiE9Ur36m9021arkk0IPccvpZjemXM8bsBDDG7BARbVLmMCmpKbz6\n/avEJ8b7HHg8QiK4q95d/LfZf7mg9AUBVKgo4cO2bWd63/z+u//rFSt2dvgmIg98ypJTL3J9NuXj\n4+NPT8fFxREXF5dD1eZNVm5fyb2f3svKHSt92nW6pBND44ZS+7zaAVKmKOHDsWNnwjdffZW58E1c\nnHX0t91m4/aBICEhgYSEhFyvJ6vhnXVAnEd4Z5Exxqvn0fCO/xw9eZShiUN55ftXOGVOudq1vagt\nw5oPo36F+gFUpyihjzHw009nwjcHDvi/brVqZ8I31avnksBMEOzwjjh/aXwK9AReAnoAc3JWVv4j\ncWMifeb2Yf0+9y8/qpWqxpi2Y2hZo2UAlSlK6LN9+5nwzTrfA7+dRdGi0KmTdfbXXZc3wjcZ4U/v\nnWlAHBAD7ASGALOBGUAVYBO2y6bXZ6q29H2TdCyJJxY8wdgVY11tBOHhxg8zrPkwikXlUlcBRQkz\njh2DuXOto//yy8yFb5o1OxO+KRGin68EtfdOtipQp+/KnN/ncP+8+9l2cJurzaXlLmV8u/FcVfmq\nACpTlNDEGPj5Z/uV7AcfwP79/q8bGws9etjwTY0auacxpwh2eEfJQXYe2smALwYwY+0MV5uCEQUZ\nfN1gBl07SHPkKPmeHTvg/fdtq/633/xfr2hRuP1226pv1ix/hG8yQp1+ADHGMPmXyTw6/1H2H3Nv\nolxd+WrG3zKeS867JIDqFCW0OH787PDNKfe+DefQtKl19J06hW74Jlio0w8Q/+z/h36f9WPBhgWu\nNsWjijPihhHcf+X9mtteyZcYAytWWEc/bRrs2+f/ulWrngnfXHhhrkkMe9Tp5zKnUk/xxo9vMHjR\nYJ9pj1tf2Jp32r5D1ZJVA6hOUUKDHTtg6lTr7Nes8X+9IkXsy9iePaF5cw3f+IM6/Vxk9c7V9J7b\nm2Vbl7naxBSJ4bWbXuOOunfoMIVKvuLECfjsM+vo583LXPjm2mvPhG+io3NLYd5EnX4ucDzlOM8v\nfp4RS0b4HK6we93uvNbqNc4rdl4A1SlK8DAGVq2yvW+mTYO9vjODn0XlyjZ806MH1KyZexrzOur0\nc5jvt3xP7097s26P+xciVaKrMLrNaNpc1CaAyhQleOzadSZ88+uv/q9XuPDZ4ZvIyNxSmH9Qp59D\nHDx+kKe/eZq3f3ob4yMV0QNXPsCIG0bogCZKnufECfj88zPhmxT3H73ncM011tF37gwlS+aWwvyJ\nOv0c4Iv1X9Dvs35sSd7ialOrbC3GtxtPk6pNAqhMUQLPqlXW0U+dCnv2+L/e+eefCd9cdFGuycv3\nqNPPBrsP7+aR+Y8wdfVUV5sCEQUY1GQQz1z3DIULFA6gOkXJfYyx/en37IGZM62z/+UX/9cvXNiO\nI9uzJ9xwg4ZvAoE6/SxgjGHa6mk8PP9h9hxxb8pcWelKxt8ynnrl62W7zpMn7TBuJ07YG6VIkbP/\nR0WFx1BtSuBJc8yHD3v/O3Qoe8szk/MmjauvPhO+KVUqx3dZ8YE6/UyyOWkz931+H/PWz3O1KVKg\nCMOvH87AqwYSGZG9psuff8KYMTB5su+eDiLeHwZp/32VZed/oUL6sMkJjLEP9Jx2yGl/mekOmVtU\nqmQ/nOrRA2p5HWdPCQSacM1PUk0qo38azaBvBnHoxCFXuxYXtGBM2zHZGsXqxAmYNcs6+0WLsryZ\ngJH+oZJbD5j0dQTjQ5z0jjmnnPKhQ6HhmHOaQoWgQwe45x5o0ULDN5lBs2wGkXW719F7bm++3/K9\nq02pwqUY2XIkPev3zPJHVn//DePGwYQJsHt3VtXmH6KisvfgKFAAjhzJnLPOTA+U/MxVV9nwTZcu\nULp0sNWEJ+r0g8CJUyd4aclLDF88nBOnTrja3X7J7bzZ+k0qFK+Q6TpOnrRJpd55Bxa4p+VRlJCl\nQAE7pGDFitCunXX2tXUEz2yjqZUDzLKty+j9aW9W71rtalOxeEVGtRlFh1odMr39TZtsq/7dd23e\nEX8oVAguvtgOHnHsGBw9eua/tkAVXxQoYAf5TvsrXvzs+YyW+yqL0szfYYU6/XQcPnGYZxc9y+s/\nvk6qce+W0OfyPvzfjf9HqcL+dz1ISbEfqYwZA198YV/e+cPFF0O/fvYlWEyM+7bTPwzSPxhy8n/a\n9An3H0BKJomMzJpD9sdRq2NW0tDwjgdfb/iavnP78s+Bf1xtLixzIePajSOuWpzf2/33X9uiHz/e\nTvtDwYL28/N+/ezgD6HaQyY1NecfMP7aBIM0x5xdh+xtuXa7VTzRmH4usu/oPh776jEmrZrkahMp\nkTx29WPEx8VTpGCRDLd56hTMn29b9Z995n9f5ho1oG9fGxctV86/dfIjqan2V0Z2HignT9qRlTLj\nqNUxK4EiJJ2+iGwEkoBU4KQxppEXm5B1+sYYZq6dyYAvBrDz8E5Xu/oV6vPuLe9yecXLM9zm9u22\n9824cTZu7w8FCthubf36wfXXa05wRVFC90VuKhBnjMnE8MShwbaD27j/8/uZ88ccV5vCBQoT3yye\nR69+lIKRBV3tUlPhm29sD5xPP/X/pWq1atCnD/TqBRUy3/FHURQl02TX6QsQVu3SVJPK+BXj+c+C\n/5B8PNnVrllsM8a1G0fNGPfE3bt22bzgY8fChg3+1R8ZCW3bQv/+cOON+rGKoiiBJbvhnQ3AAeAU\nMNYYM86LTciEd9bvXU+fuX1I3JToahNdKJqXb3yZ3pf39jpOrTGQkGBj9Z98YuPC/lC5sm3V33uv\nzSaoKIrii1AN7zQxxmwXkfOABSKyzhizJL1RfHz86em4uDji4uKyWW3mSElN4dXvXyU+MZ5jKe7d\nPm65+BZG3TyK86PP9cp799oMgmPH2nw4/iACN99sY/WtW9vYvaIoijcSEhJISEjI9XpyrPeOiAwB\nDhpjRqZbHtSW/srtK7n303tZuWOlq025YuV4q/Vb3H7J7WelUDAGliyxrfqZM22mQn+oWNG26Hv3\nhtjY7O6Boij5kZBr6YtIUSDCGHNIRIoBLYGhOaYsmxw9eZShiUN55ftXOGXcM1n1rN+TV1u+Spki\nZU4v278f3nvPOvu1a/2vs1Ur26pv29b2s1cURQk1shNwKA/MEhHjbGeqMearnJGVPRI3JtJnbh/W\n7ySScF8AAAnlSURBVFvvalOtVDXGth3LjTVuBGyr/scfbQ+c6dP9//inXDnb+6ZPH7gg64k1FUVR\nAkKe+jgr6VgSTyx4grErxrrrQXi48cMMaz6MYlHFSE6G99+3rfrMDNh8/fW2B0779vqJu6IoOU/I\nhXdCjTm/z+H+efez7eA2V5tLy13K+HbjuaryVSxfbh39tGk2va4/xMTYvOB9+0JN956ciqIoIUvY\nO/2dh3Yy4IsBzFg7w9UmKjKKwU0H80D9J/n4oyjufwdWrPC/juuus7H6W2+1edgVRVHClbB1+sYY\nJv8ymUfnP8r+Y+4fBF9T5RoevXAcX39wCdXawcGD/m2/VCk7rFu/fpobXFGUvENYxvT/2f8P/T7r\nx4IN7qOOFC9YnPbFR7B+2v0s+9H/j4avucY6+k6d7AhLiqIowSAkE675VUEOOv1Tqad448c3GLxo\nMEdOugfiY0+0Zt+Udzj4b1W/thsdDXfdZZ193bo5IlVRFCVb5Hunv3rnanrP7c2yrctcbQqciCFl\n7uuwujs2LZBvrrzS9sDp0sWmzlUURQkV8m3vneMpxxn+7XBe/O5FUlJ9pK/8tTspX74GR87zub3i\nxeGOO2yrvkGDHBarKIoS4oS00/9+y/f0/rQ36/asczdKqgKfjYb1bXxuq0ED6+i7d4cSJXJYqKIo\nSpgQkk7/4PGDPP3N07z909sYXEJDRuCn++HrEXDCuxcvWhS6dbPOvmFDHfFIURQl5Jz+vPXz6P9Z\nf7Ykb3E32l0LPh0PW5p4La5b1zr6O++EkiVzSaiiKEoYEjJOf/fh3Tw8/2GmrZ7mbnSqACwZBIuf\ngZSzv5IqXBg6d7bO/uqrtVWvKIrijaA7fWMM01ZP4+H5D7PnyB53w61X2tb9znpnLa5Vy/bAuesu\nKFPGZV1FURQFCLLT35y0mXtm3sfCf+e5G50sAt88Dz8+BMaOLRgVBbffblv1TZtqq15RFMVfguL0\nT6akMuC9UYz/5ylORR5yN/y7BXw2BvbbnMU1a9pkZz17QtmygdGqKIqSlwio09+2DV4cv44xO3pz\novz34DYo+NFSMH8krOpJgQJCx042hBMXBxFhNQy7oihKaBGQL3K//NIweuwJPt33Euba4VDghPsK\nv3WCL96g+nkV6NvXpjIuXz5XJSqKooQcYZ2GgfN/hFt6Q/nV7obJlYj4YhTta7Wnf39o0UJb9Yqi\n5F/COw3DvVdDRKprcbHf+zLwkpd44OtSVKoUEEWKoij5kmw5fRG5CXgNiADeNca85NXQxeEXO3Yh\nz9QbxxOD44h0i+8riqIoOUaWAygiEgG8BbQC6gDdRKSWX+uaSO6r+yS7n/uVp7oFx+EnJCQEvtIs\nEC46IXy0hotOCB+tqjN8yE7UvBGw3hizyRhzEvgQaJ/RSvXLN2B5v2WMuvVFihQM3igl4XLyw0Un\nhI/WcNEJ4aNVdYYP2XH65wOeCXL+dZZ5pXCBwrx4w4ss6/Mjl1e8PBvVKoqiKFklIC9ym8U2Y1y7\ncdSMqRmI6hRFURQXstxlU0QaA/HGmJuc+UGASf8yV0Ryt0+ooihKHiWk+umLSCTwB3ADsB1YBnQz\nxvgY8URRFEUJJlkO7xhjTonIg8BXnOmyqQ5fURQlhMn1L3IVRVGU0CGsEx2IyLsislNEfvVYVlpE\nvhKRP0RkvoiU9Ch7SkTWi8g6EWnpsfxyEflVRP4Ukdc8lkeJyIfOOktFpGoWdVYWkYUi8puIrBaR\nh0JYayER+VFEVjpah4SqVmdbESKyQkQ+DVWdIrJRRH5xjumyUNXpbKukiMxw6v5NRK4KNa0icpFz\nLFc4/5NE5KFQ0+ls5xERWePUMdXZbnB1GmPC9g+4FqgP/Oqx7CXgCWf6SeBFZ/oSYCU2pFUN+Isz\nv3R+BK50pucBrZzp+4BRznQX4MMs6qwA1Hemi2PfhdQKRa3O+kWd/5HAD9hvMkJV6yPA+8CnIXz+\nNwCl0y0LOZ3O+pOAe5zpAkDJUNXqbCMC2AZUCTWdQCXn3Ec589OBHsHWGTSHnVN/QCxnO/3fgfLO\ndAXgd2d6EPCkh90XwFWOzVqP5V2B0c70l8BVznQksDuHNM8GWoS6VqAosBy4MhS1ApWBBUAcZ5x+\nKOr8B4hJtywUdUYDf3tZHnJaPbbdElgcijqxTn8TUBrryD8lBO77sA7vuFDOGLMTwBizAyjnLE//\nMdlWZ9n52A/L0vD8yOz0OsaYU8ABEcnWoIwiUg376+QH7IkPOa1OyGQlsANYYIz5KUS1/g/4D2A8\nloWiTgMsEJGfRKR3COusDuwRkYlO6GSsiBQNUa1pdAHSBtYOKZ3GmG3Aq8Bmp84kY8zXwdaZF51+\nekzGJn6TrT6zIlIcmAkMNMYc4lxtIaHVGJNqjGmAbUk3EpE6hJhWEWkD7DTGrMpg/VA4pk2MMZcD\nNwMPiEhTQux4OhQALgfedvQexrY+Q1ErIlIQuAWY4SwKKZ0iUgqbmiYW2+ovJiJ3eNEVUJ150env\nFJHyACJSAdjlLN+KjfulUdlZ5rb8rHXEfpcQbYzZlxVRIlIA6/DfM8bMCWWtaRhjkoEE4KYQ1NoE\nuEVENgAfANeLyHvAjhDTiTFmu/N/Nza014jQO55gW5BbjDHLnfmPsQ+BUNQK0Br42Riz5//bu3vW\nqIIwDMP3W0j8QBCx9otgpVgIIlpYRP0DImih0X/hR+FvCPaCrYWiNiKSWhQlJJoUgoKCjSCkTBHG\nYmbxaCUuZMd97wsCZ4fdsw8b8uzZmZOz7XZvOc8Bn0opP9pR+GPg9KRzTkPpB7+/uz0FrrfteeDJ\nYPxyW+0+BMwCr9vHq/WIOBkRAVz74zHzbfsSsDhGzvvUebmFnrNGxL7R2QQRsQM4D6z1lrWUcruU\nsr+Ucpg6x7lYSrkKPOspZ0TsbJ/wiIhd1DnoFTp7PQHalMPXiDjShuaADz1mba5Q3/BHesv5BTgV\nEdvb/ueA1YnnHGcRZdI/1Lm8b8BGe4FvUBdNXlLPkHkB7Bnc/xZ1RXwNuDAYP0H9Q/wILAzGZ4CH\nbfwVcPAfc54BNoEl6ur8O+rR894Osx5r+ZaAZeBOG+8u62B/Z/m1kNtVTuo8+ej3vgLc7DHnYF/H\ngTct8yPq2TvdZaWeZPAd2D0Y6zHn3facy8ADYNukc/rPWZKUyDRM70iS/pKlL0mJWPqSlIilL0mJ\nWPqSlIilL0mJWPqSlIilL0mJWPpKJyIORMRqu4rk+4h4HhEzk84lbQVLX1nNAvdKKUeBdeDihPNI\nW8LSV1afSykrbfst9ZuKpKln6SurjcH2JvVa8tLUs/SV1VhfiCP9ryx9ZeXlZZWSl1aWpEQ80pek\nRCx9SUrE0pekRCx9SUrE0pekRCx9SUrE0pekRCx9SUrkJ1b9/UB1A1asAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x206fa1550>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "df = pd.DataFrame(snn_results)[['n', 'snn_time', 'bf_time']]\n",
    "df.plot(x='n', linewidth=5,\n",
    "        title='Time per query for bruteforce increases linearly\\nfor pysparnn it grows somewhat like a square root')"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
